using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms.Design;
using System.Windows.Forms;
using System.ComponentModel.Design;
using System.Reflection;
using System.Resources;
using System.IO;
using System.Collections;
using System.Drawing;
using System.Xml;

namespace SBPweb.Themes.Windows.Skins
{
	/// <summary>
	/// Class of Skin
	/// </summary>
	[TypeConverter(typeof(ExpandableObjectConverter))]
	public class Skin
	{
		#region Private fields
		
		private Dictionary<string, object> mResources;
		private List<string> mSkinInfo;
		private XmlDocument mSkinXml;
		private SkinCacher skinCacher;
		private System.Drawing.Text.TextRenderingHint mTextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
		private Assembly assembly;

		#endregion

		#region Constuctors

		/// <summary>
		/// Constructor of Skin
		/// </summary>
		/// <param name="asm"></param>
		public Skin(Assembly asm)
		{
			if (IsSkinPackage(asm))
			{
				throw new Exception("This is a SkinPackage assembly!");
			}

			assembly = asm;

			string[] names = asm.GetManifestResourceNames();

			mResources = ExtractResources(asm.GetManifestResourceStream(names[0]));
			mSkinInfo = ExtractSkinInfo(asm.GetManifestResourceStream(names[1]));
			mSkinXml = CreateSkinXml(mResources[KeyPrefix + "skin.xml"].ToString());

			skinCacher = new SkinCacher(this);
		}

		#endregion

		#region Public properties

		/// <summary>
		/// Name
		/// </summary>
		[Browsable(true)]
		public string Name
		{
			get
			{
				return mSkinInfo[0];
			}
		}

		/// <summary>
		/// Key prefix
		/// </summary>
		[Browsable(false)]
		public string KeyPrefix
		{
			get
			{
				return mSkinInfo[1];
			}
		}

		/// <summary>
		/// Text rendering hint
		/// </summary>
		[Browsable(true)]
		public System.Drawing.Text.TextRenderingHint TextRenderingHint
		{
			get
			{
				return mTextRenderingHint;
			}
			set
			{
				mTextRenderingHint = value;
			}
		}

		/// <summary>
		/// Cached properties
		/// </summary>
		public SkinCacher CachedProperties
		{
			get 
			{ 
				return skinCacher; 
			}
		}

		/// <summary>
		/// Underlying assembly
		/// </summary>
		public Assembly UnderlyingAssembly
		{
			get
			{
				return assembly;
			}
		}

		#endregion

		#region Public methods

		/// <summary>
		/// Get bitmap resource
		/// </summary>
		/// <param name="key">key</param>
		/// <returns>bitmap</returns>
		public Bitmap GetBitmapResource(string key)
		{
			Bitmap value = null;
			if (mResources.ContainsKey(key))
			{
				value = mResources[key] as Bitmap;
			}

			return value;
		}

		/// <summary>
		/// Get imaeg from bitmap resource
		/// </summary>
		/// <param name="key">key</param>
		/// <returns>image</returns>
		public Image GetImageFromBitmapResource(string key)
		{
			Bitmap value = null;
			Image image = null;
			if (mResources.ContainsKey(key))
			{
				value = mResources[key] as Bitmap;
				image = value.GetThumbnailImage(value.Width, value.Height, null, IntPtr.Zero);
			}

			return image;
		}

		/// <summary>
		/// ToString
		/// </summary>
		/// <returns>string</returns>
		public override string ToString()
		{
			return Name;
		}

		/// <summary>
		/// Select a single node
		/// </summary>
		/// <param name="path"></param>
		/// <returns></returns>
		public XmlNode SelectSingleNode(string path)
		{
			string xpath = string.Format("Skins/*/{0}", path);
			XmlNode node = mSkinXml.SelectSingleNode(xpath);

			return node;
		}

		#endregion

		#region Public static helpers

		/// <summary>
		/// Is skin package?
		/// </summary>
		/// <param name="asm">assembly</param>
		/// <returns>true or false</returns>
		public static bool IsSkinPackage(Assembly asm)
		{
			string[] names = asm.GetManifestResourceNames();

			return names[0] != "SkinData.resources";
		}

		#endregion

		#region Private helper methods
		
		private static List<string> ExtractSkinInfo(Stream info)
		{
			ResourceReader resourceReader = new ResourceReader(info);
			IDictionaryEnumerator ide = resourceReader.GetEnumerator();
			List<string> infoList = new List<string>();

			while (ide.MoveNext())
			{
				string[] list = ide.Value as string[];
				infoList = new List<string>(list);
			}

			return infoList;
		}

		private static Dictionary<string, object> ExtractResources(Stream data)
		{
			ResourceReader resourceReader = new ResourceReader(data);
			IDictionaryEnumerator ide = resourceReader.GetEnumerator();
			Dictionary<string, object> resources = new Dictionary<string, object>();

			while (ide.MoveNext())
			{
				resources.Add(ide.Key.ToString(), ide.Value);
			}

			return resources;
		}

		private static XmlDocument CreateSkinXml(string xml)
		{
			XmlDocument skinXml = new XmlDocument();
			skinXml.LoadXml(xml);

			return skinXml; 
		}
		
		#endregion
	}
}
